﻿using System.Collections.Generic;
using System.Linq;

namespace Red.Launcher.ViewModels.Workspaces.Database.Sql
{
    /// <summary>
    /// A class representing an sql select query
    /// </summary>
    public partial class Select : IAlias, ISql, ISqlDeclaration
    {
        #region Private Data

        private List<ISqlDeclaration> _columns = new List<ISqlDeclaration>();
        private List<ISqlDeclaration> _sources = new List<ISqlDeclaration>();
        private List<ISqlDeclaration> _groupBy = new List<ISqlDeclaration>();
        private ConditionCollection _conditions = new ConditionCollection();

        #endregion Private Data

        #region Public Properties

        /// <summary>
        /// The data being retrieved
        /// </summary>
        public ICollection<ISqlDeclaration> Columns => _columns;

        /// <summary>
        /// The tables/joins/others from which data is being retrieved
        /// </summary>
        public ICollection<ISqlDeclaration> Sources => _sources;

        /// <summary>
        /// The comparisons performed in the WHERE clause
        /// </summary>
        public ConditionCollection Conditions => _conditions;

        /// <summary>
        /// The elements referenced in the GROUP BY clause
        /// </summary>
        public ICollection<ISqlDeclaration> GroupBy => _groupBy;

        /// <summary>
        /// A name by which this select query can be referenced elsewhere in the sql
        /// </summary>
        public string Alias { get; set; }

        /// <summary>
        /// The generated GROUP BY clause
        /// </summary>
        public string GroupBySql
        {
            get
            {
                if ( GroupBy.Count > 0 )
                {
                    return "\nGROUP BY " + string.Join( ", ", from column in GroupBy select column.SqlDeclaration );
                }

                return string.Empty;
            }
        }

        /// <summary>
        /// The complete select query
        /// </summary>
        public string Sql
        {
            get
            {
                return string.Format
                (
                    "\n(SELECT {0}\nFROM {1}\n{2}{3})",
                    string.Join( ", ", from column in Columns select column.SqlDeclaration ),
                    string.Join( "\n", from source in Sources select source.SqlDeclaration ),
                    Conditions.Sql,
                    GroupBySql
                );
            }
        }

        /// <summary>
        /// The complete select query with alias (if applicable)
        /// </summary>
        /// <remarks>
        /// If no alias is defined, this code is identical to Sql
        /// </remarks>
        public string SqlDeclaration => Sql + this.GetAliasDeclaration();

        #endregion Public Properties

        #region Public Methods

        /// <summary>
        /// Utility function to reduce boilerplate bloat
        /// </summary>
        public Column AddColumn( string name, IAlias source = null, string alias = null, string func = null )
        {
            Column column = new Column()
            {
                Name = name,
                Source = source,
                Alias = alias,
                Function = func
            };

            Columns.Add( column );

            return column;
        }

        #endregion Public Methods
    }
}
